package com.czm.test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author CZM
 * @date 2022 06 16 22:28
 */
public class Day09 {
    public static void main(String[] args) {
//        test086();
//        test085();

//        test084();
//        test0842();
//        test0843();

//        char[] chars = {'a','b','1','9'};
//
//        System.out.println(chars[0]);
//        System.out.println(chars[1]);
//        System.out.println(chars[2]);
//        System.out.println(chars[0] + chars[1]);
//        System.out.println(chars[1] + chars[2]);
//        System.out.println(chars[2] + chars[3]);
//
//        System.out.println(Character.digit(chars[0], 1000));
//        System.out.println(Character.digit(chars[0], 2));
//        System.out.println(Character.digit(chars[2], 10));
//        System.out.println(Character.digit(chars[2], 2));
//        System.out.println(Character.digit(chars[3], 10));
//        System.out.println(Character.digit(chars[3], 8));

//        int sum = 10;
//        System.out.println(sum += Integer.parseInt("-78"));

//        test082();

       test079();
//        test078();
//        test077();
//         test076();
//         test0843();
    }

    /**
     * 给定一个射击比赛成绩单
     包含多个选手若干次射击的成绩分数
     请对每个选手按其最高三个分数之和进行降序排名
     输出降序排名后的选手id序列
     条件如下
     1. 一个选手可以有多个射击成绩的分数，且次序不固定
     2. 如果一个选手成绩少于3个，则认为选手的所有成绩无效，排名忽略该选手
     3. 如果选手的成绩之和相等，则相等的选手按照其id降序排列

     输入描述:
     输入第一行
     一个整数N
     表示该场比赛总共进行了N次射击
     产生N个成绩分数
     2<=N<=100

     输入第二行
     一个长度为N整数序列
     表示参与每次射击的选手id
     0<=id<=99

     输入第三行
     一个长度为N整数序列
     表示参与每次射击选手对应的成绩
     0<=成绩<=100

     输出描述:
     符合题设条件的降序排名后的选手ID序列

     示例一
     输入:
     13
     3,3,7,4,4,4,4,7,7,3,5,5,5
     53,80,68,24,39,76,66,16,100,55,53,80,55
     输出:
     5,3,7,4
     说明:
     该场射击比赛进行了13次
     参赛的选手为{3,4,5,7}
     3号选手成绩53,80,55 最高三个成绩的和为188
     4号选手成绩24,39,76,66  最高三个成绩的和为181
     5号选手成绩53,80,55  最高三个成绩的和为188
     7号选手成绩68,16,100  最高三个成绩的和为184
     比较各个选手最高3个成绩的和
     有3号=5号>7号>4号
     由于3号和5号成绩相等  且id 5>3
     所以输出5,3,7,4
     */
    public static void test086() {
        Scanner sc = new Scanner(System.in);
        String line1 = sc.nextLine();
        String line2 = sc.nextLine();
        String line3 = sc.nextLine();
        String[] strings2 = line2.split(",");
        String[] strings3 = line3.split(",");
        // 用Map存储，key存选手号，value用list存选手所有的成绩
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < Integer.parseInt(line1); i++) {
            if (map.containsKey(Integer.parseInt(strings2[i]))) {
                List<Integer> list = map.get(Integer.parseInt(strings2[i]));
                list.add(Integer.parseInt(strings3[i]));
            } else {
                List<Integer> list = new ArrayList<>();
                list.add(Integer.parseInt(strings3[i]));
                map.put(Integer.parseInt(strings2[i]), list);
            }
        }
        Map<Integer, Integer> map2 = new HashMap();
        // 遍历Map，对选手成绩进行筛选，用一个Map<Integer, Integer>来存选手号和最大成绩
        for (Integer key : map.keySet()) {
            List<Integer> list = map.get(key);
            int listSize = list.size();
            if (listSize >= 3) {
                Collections.sort(list);
                int listAll = list.get(listSize - 1) + list.get(listSize - 2) + list.get(listSize - 3);
                map2.put(key, listAll);
            }
        }
        StringBuilder builder = new StringBuilder();
        // 通过stream流的形式进行排序     sorted：对集合进行排序  e1与e2比较，结果大于0互换位置 小于等于0不变
        Set<Map.Entry<Integer, Integer>> entries = map2.entrySet();
        entries.stream().sorted((e1, e2) -> {
            if (e1.getValue().equals(e2.getValue())) {
                // 分数相等，选手号大的在前
                return e2.getKey() - e1.getKey();
            } else {
                // 分数大的在前
                return e2.getValue() - e1.getValue();
            }
        }).forEach((e) -> {
            builder.append(e.getKey() + ",");
        });
        System.out.println(builder.substring(0, builder.length() - 1));
    }

    /*
    有一个特殊的五键键盘
    上面有A、Ctrl-C、Ctrl-X、Ctrl-V、Ctrl-A
    A键在屏幕上输出一个字母A
    Ctrl-C将当前所选的字母复制到剪贴板
    Ctrl-X将当前选择的字母复制到剪贴板并清空所选择的字母
    Ctrl-V将当前剪贴板的字母输出到屏幕
    Ctrl-A选择当前屏幕中所有字母
    注意：
      1. 剪贴板初始为空
      2. 新的内容复制到剪贴板会覆盖原有内容
      3. 当屏幕中没有字母时,Ctrl-A无效
      4. 当没有选择字母时Ctrl-C、Ctrl-X无效
      5. 当有字母被选择时A和Ctrl-V这两个输出功能的键,
         会先清空所选的字母再进行输出

    给定一系列键盘输入,
    输出最终屏幕上字母的数量

    输入描述:
       输入为一行
       为简化解析用数字12345分别代替A、Ctrl-C、Ctrl-X、Ctrl-V、Ctrl-A的输入
       数字用空格分割

    输出描述:
        输出一个数字为屏幕上字母的总数量

    示例一:
        输入:
          1 1 1
        输出:
          3

   示例二:
        输入:
          1 1 5 1 5 2 4 4
        输出:
          2
   */
    // 计算屏幕字幕数量
    public static void test085() {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] split = line.split(" ");
        // 屏幕内容
        int result = 0;
        // 剪切板内容
        int ctrl_c_x = 0;
        // ctrl_A选中的内容
        int ctrl_a = 0;
        for (int i = 0; i < split.length; i++) {

            if (1 == Integer.parseInt(split[i])) { // A
                // Ctrl-A 选中内容，输入A则覆盖，屏幕内容长度为1
                if (ctrl_a != 0) {
                    result = 1;
                } else { // Ctrl-A 没选中内容，输入A屏幕内容长度加1
                    result++;
                }
                ctrl_a = 0;
            } else if (2 == Integer.parseInt(split[i])) { // Ctrl-C
                // 当Ctrl-A 选中内容时，Ctrl-C才有效
                if (0 != ctrl_a) {
                    // 剪切板内容等于ctrl_A选中的内容
                    ctrl_c_x = ctrl_a;
                }
            } else if (3 == Integer.parseInt(split[i])) { // Ctrl-X
                // 当Ctrl-A 选中内容时，Ctrl-X才有效
                if (0 != ctrl_a) {
                    // 剪切板内容等于ctrl_A选中的内容
                    ctrl_c_x = ctrl_a;
                    // Ctrl-X后屏幕内容长度为0
                    result = 0;
                    // Ctrl-X后ctrl_A选中内容长度为0
                    ctrl_a = 0;
                }
            } else if (4 == Integer.parseInt(split[i])) { // Ctrl-V
                // 当剪切板有内容ctrl_v才有用    // PS:这里有个疑问：当剪切板为空时，使用Ctrl-V是用空覆盖还是无效呢？？我的处理是无效，我觉得这里题目描述的不是很清楚
                if (0 != ctrl_c_x) {
                    // Ctrl-A 选中内容时
                    if (ctrl_a != 0) {
                        result = ctrl_c_x;
                        ctrl_a = 0;
                    } else if (ctrl_a == 0) { // Ctrl-A 没选中内容时
                        result += ctrl_c_x;
                    }
                }
            } else if (5 == Integer.parseInt(split[i])) { // Ctrl-A
                // 选中屏幕所有内容
                ctrl_a = result;
            }
        }
        System.out.println(result);
    }

    /**
     *
     */
    public static void test084() {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] split = line.split(",");
        List<String> list = new ArrayList<>();
        for (int i = 0; i < split.length; i++) {
            list.add(split[i]);
        }
        list.sort((a1, a2) -> {
            // 长度相同，直接比较大小
            if (a1.length() == a2.length()) {
                return Integer.parseInt(a2) - Integer.parseInt(a1);
            }
            String[] split1 = a1.split("");
            String[] split2 = a2.split("");
            int min = Math.min(split1.length, split2.length);
            for (int i = 0; i < min; i++) {
                if (Integer.parseInt(split1[i]) != Integer.parseInt(split2[i])) {
                    return Integer.parseInt(split2[i]) - Integer.parseInt(split1[i]);
                }
            }
            // 这里处理有瑕疵，通过率没有100%，当11,111113这种前面相等，后面还是相等的情况过不了
            if (split1.length > split2.length) {
                return Integer.parseInt(split1[0]) - Integer.parseInt(split1[min]);
            } else {
                return Integer.parseInt(split2[min]) - Integer.parseInt(split2[0]);
            }
        });
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i));
        }
    }

    public static void test0842() {
        Scanner in = new Scanner(System.in);
        String nums = in.nextLine();
        in.close();

        StringBuilder builder = new StringBuilder();

        Arrays.stream(nums.split(","))
                .sorted((s1, s2) -> {
                    char[] v1 = s1.toCharArray();
                    char[] v2 = s2.toCharArray();
                    int len1 = v1.length;
                    int len2 = v2.length;

                    if (len1 == len2) {
                        return s2.compareTo(s1);
                    }

                    int min = Math.min(len1, len2);
                    for (int i = 0; i < min; i++) {
                        char c1 = v1[i];
                        char c2 = v2[i];
                        if (c1 != c2) {
                            return c2 - c1;
                        }
                    }

                    if (len1 > len2) {
                        return v1[0] - v1[min];
                    } else {
                        return v2[min] - v2[0];
                    }
                })
                .forEach(builder::append);

        System.out.println(builder);

    }

    /*
小组中每位都有一张卡片
卡片是6位以内的正整数
将卡片连起来可以组成多种数字
计算组成的最大数字

输入描述：
  ","分割的多个正整数字符串
  不需要考虑非数字异常情况
  小组种最多25个人

 输出描述：
   最大数字字符串

 示例一
   输入
    22,221
   输出
    22221

  示例二
    输入
      4589,101,41425,9999
    输出
      9999458941425101
 */
    // 100%通过解法
    // 组成最大数字
    public static void test0843() {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] split = line.split(",");
        // 类似于冒泡排序，用双层for循环，将最大的组合往前放
        for (int i = 0; i < split.length - 1; i++) {
            for (int j = i + 1; j < split.length; j++) {
                String res1 = split[i] + split[j];
                String res2 = split[j] + split[i];
                if (Integer.parseInt(res1) < Integer.parseInt(res2)) {
                    String value = split[i];
                    split[i] = split[j];
                    split[j] = value;
                }
            }
        }
        for (int i = 0; i < split.length; i++) {
            System.out.print(split[i]);
        }
    }

    /**
     * 1.输入字符串s输出s中包含所有整数的最小和，
     * 说明：1字符串s只包含a~z,A~Z,+,-，
     * 2.合法的整数包括正整数，一个或者多个0-9组成，如：0,2,3,002,102
     * 3.负整数，负号开头，数字部分由一个或者多个0-9组成，如-2,-012,-23,-00023
     * 输入描述：包含数字的字符串
     * 输出描述：所有整数的最小和
     * 示例：
     * 输入：
     * bb1234aa
     * 　输出
     * 10
     * 　输入：
     * bb12-34aa
     * 　输出：
     * -31
     * 说明：1+2-(34)=-31
     */
    // 输出字符串中最小数字
    public static void test082_2() {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        // 将字符串转为字符数组
        char[] chars = line.toCharArray();
        // 累加结果
        int sum = 0;
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (c == '-') {
                int start = i;
                i++;
                while (i < chars.length && Character.isDigit(chars[i])) {
                    i++;
                }
                // 截取负数
                String substring = line.substring(start, i);
                // 当substring = 1时只有一个负号
                if (substring.length() > 1) {
                    sum += Integer.parseInt(substring);
                }
            }

            // 判断字符是不是数字
            if (Character.isDigit(c)) {
                // 将字符数字转为数字,当字符数字小于第二个参数时，返回-1
                sum += Character.digit(c, 10);
            }
        }

        System.out.println(sum);
    }


    /**
     * 某学校举行运动会,学生们按编号（1、2、3.....n)进行标识,
     * 现需要按照身高由低到高排列，
     * 对身高相同的人，按体重由轻到重排列，
     * 对于身高体重都相同的人，维持原有的编号顺序关系。
     * 请输出排列后的学生编号
     * 输入描述：
     * 两个序列，每个序列由N个正整数组成，(0<n<=100)。
     * 第一个序列中的数值代表身高，第二个序列中的数值代表体重，
     * 输出描述：
     * 排列结果，每个数据都是原始序列中的学生编号，编号从1开始，
     * 实例一：
     * 输入:
     * 4
     * 100 100 120 130
     * 40 30 60 50
     * 输出:
     * 2134
     */
    // 多条件排列
    public static void test079() {
        Scanner sc = new Scanner(System.in);
        int len = Integer.parseInt(sc.nextLine());
        // 身高
        String line1 = sc.nextLine();
        // 体重
        String line2 = sc.nextLine();
        String[] split1 = line1.split(" ");
        String[] split2 = line2.split(" ");
        // map的key为编号，value为学生的身高、体重组成的list
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 1; i <= len; i++) {
            List<Integer> list = new ArrayList<>();
            // 身高
            list.add(Integer.parseInt(split1[i - 1]));
            // 体重
            list.add(Integer.parseInt(split2[i - 1]));
            map.put(i, list);
        }

        Set<Map.Entry<Integer, List<Integer>>> entrySet = map.entrySet();
        // 通过stream流的形式进行排序     sorted：对集合进行排序  s1与s2比较，结果大于0互换位置 小于等于0不变
        entrySet.stream().sorted((s1, s2) -> {
            List<Integer> value1 = s1.getValue();
            List<Integer> value2 = s2.getValue();
            // 身高相等比体重
            return value1.get(0) == value2.get(0) ? value1.get(1) - value2.get(1) : value1.get(0) - value2.get(0);
        }).forEach((s) -> {
            System.out.print(s.getKey());
        });
    }

    /**
     * 运维工程师采集到某产品线网运行一天产生的日志n条
     * 现需根据日志时间先后顺序对日志进行排序
     * 日志时间格式为H:M:S.N
     * H表示小时(0~23)
     * M表示分钟(0~59)
     * S表示秒(0~59)
     * N表示毫秒(0~999)
     * 时间可能并没有补全
     * 也就是说
     * 01:01:01.001也可能表示为1:1:1.1
     * <p>
     * 输入描述
     * 第一行输入一个整数n表示日志条数
     * 1<=n<=100000
     * 接下来n行输入n个时间
     * <p>
     * 输出描述
     * 按时间升序排序之后的时间
     * 如果有两个时间表示的时间相同
     * 则保持输入顺序
     * <p>
     * 示例：
     * 输入：
     * 2
     * 01:41:8.9
     * 1:1:09.211
     * 输出
     * 1:1:09.211
     * 01:41:8.9
     * 示例
     * 输入
     * 3
     * 23:41:08.023
     * 1:1:09.211
     * 08:01:22.0
     * 输出
     * 1:1:09.211
     * 08:01:22.0
     * 23:41:08.023
     * <p>
     * 示例
     * 输入
     * 2
     * 22:41:08.023
     * 22:41:08.23
     * 输出
     * 22:41:08.023
     * 22:41:08.23
     * 时间相同保持输入顺序
     */
    // 时间排序
    public static void test078() {
        Scanner sc = new Scanner(System.in);
        // 输入的个数
        int len = Integer.parseInt(sc.nextLine());
        List<String> list = new ArrayList<>();
        int i = 0;
        while (i < len) {
            list.add(sc.nextLine());
            i++;
        }
        sc.close();
        // 对集合进行排序  a1与a2比较，结果大于0互换位置 小于等于0不变
        list.stream().sorted((a1, a2) -> {
            // 根据规则切分出时 分 秒 毫秒
            String[] time1 = a1.split(":");
            String[] time2 = a2.split(":");

            // 用.进行分割时需要用到转义字符 \\
            String[] s_n1 = time1[2].split("\\.");
            String[] s_n2 = time2[2].split("\\.");
            int h1 = Integer.parseInt(time1[0]);
            int h2 = Integer.parseInt(time2[0]);
            int m1 = Integer.parseInt(time1[1]);
            int m2 = Integer.parseInt(time2[1]);
            int s1 = Integer.parseInt(s_n1[0]);
            int s2 = Integer.parseInt(s_n2[0]);
            int n1 = Integer.parseInt(s_n1[1]);
            int n2 = Integer.parseInt(s_n2[1]);

            // 小时不相等比较小时
            if (h1 != h2) {
                return h1 - h2;
            }
            // 分钟不相等比较分钟
            if (m1 != m2) {
                return m1 - m2;
            }
            // 秒不相等比较秒
            if (s1 != s2) {
                return s1 - s2;
            }
            // 毫秒不相等比较毫秒
            if (n1 != n2) {
                return n1 - n2;
            }
            // 都相等按原来顺序
            return 0;
        }).forEach((a) -> {
            System.out.println(a);
        });
    }

    /**
     * 双十一众多商品进行打折销售
     * 小明想购买自己心仪的一些物品
     * 但由于购买资金限制
     * 所以他决定从众多心仪商品中购买三件
     * 而且想尽可能得花完资金
     * 现在请你设计一个程序 计算小明尽可能花费的最大资金数
     * <p>
     * 输入描述：
     * 输入第一行为一维整型数组m
     * 数组长度小于100
     * 数组元素记录单个商品的价格
     * 单个商品加个小于1000
     * <p>
     * 输入第二行为购买资金的额度r
     * r<100000
     * <p>
     * 输出描述：
     * 输出为满足上述条件的最大花费额度
     * <p>
     * 注意：如果不存在满足上述条件的商品请返回-1
     * <p>
     * 示例：
     * 输入
     * 23,26,36,27
     * 78
     * 输出
     * 76
     * 说明：
     * 金额23、26、27得到76而且最接近且小于输入金额78
     * <p>
     * 示例：
     * 输入
     * 23,30,40
     * 26
     * 输出
     * -1
     * 说明
     * 因为输入的商品无法满足3件之和小于26
     * 故返回-1
     * <p>
     * 输入格式正确无需考虑输入错误情况
     */
    // 满足最大话费额度
    public static void test077() {
        Scanner sc = new Scanner(System.in);
        String line1 = sc.nextLine();
        String line2 = sc.nextLine();
        String[] split = line1.split(",");
        int len = split.length;
        int sum = 0;
        // 依次遍历，列出所有的三数之和
        for (int i = 0; i < len - 2; i++) {
            for (int j = i + 1; j < len - 1; j++) {
                for (int k = j + 1; k < len; k++) {
                    int res = Integer.parseInt(split[i]) + Integer.parseInt(split[j]) + Integer.parseInt(split[k]);
                    if (res < Integer.parseInt(line2)) {
                        // 与原来的值比较，留下大的值
                        sum = Math.max(sum, res);
                    }
                }
            }
        }
        if (sum == 0) {
            System.out.println(-1);
        } else {
            System.out.println(sum);
        }
    }

    /**
     * 在学校中
     * N个小朋友站成一队
     * 第i个小朋友的身高为height[i]
     * 第i个小朋友可以看到第一个比自己身高更高的小朋友j
     * 那么j是i的好朋友
     * (要求：j>i)
     * 请重新生成一个列表
     * 对应位置的输出是每个小朋友的好朋友的位置
     * 如果没有看到好朋友
     * 请在该位置用0代替
     * 小朋友人数范围 0~40000
     * <p>
     * 输入描述：
     * 第一行输入N
     * N表示有N个小朋友
     * <p>
     * 第二行输入N个小朋友的身高height[i]
     * 都是整数
     * <p>
     * 输出描述：
     * 输出N个小朋友的好朋友的位置
     * <p>
     * 示例1：
     * 输入：
     * 2
     * 100 95
     * 输出
     * 0 0
     * 说明
     * 第一个小朋友身高100站在队伍末尾
     * 向队首看 没有比他身高高的小朋友
     * 所以输出第一个值为0
     * 第二个小朋友站在队首前面也没有比他身高高的小朋友
     * 所以输出第二个值为0
     * <p>
     * 示例2：
     * 输入
     * 8
     * 123 124 125 121 119 122 126 123
     * 输出
     * 1 2 6 5 5 6 0 0
     * 说明：
     * 123的好朋友是1位置上的124
     * 124的好朋友是2位置上的125
     * 125的好朋友是6位置上的126
     * 依此类推
     */
    // 小朋友身高位置
    public static void test076() {
        Scanner sc = new Scanner(System.in);
        // 数组长度
        int len = Integer.parseInt(sc.nextLine());
        String line = sc.nextLine();
        String[] split = line.split(" ");
        // 双层循环，依次往后比较
        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) {
                if (Integer.parseInt(split[i]) < Integer.parseInt(split[j])) {
                    System.out.print(j + " ");
                    break;
                }
                // 当看到最后一个，还没结束，说明没有，输出0
                if (j == len - 1) {
                    System.out.print(0 + " ");
                }
            }
        }
        // 队首直接输出0
        System.out.print(0);
    }

    public static void test_076_2() {
        Scanner in = new Scanner(System.in);
        int n = Integer.parseInt(in.nextLine());

        if (n == 0) {
            System.out.println(0);
            return;
        }
        String[] strs = in.nextLine().split(" ");

        List<Integer> height = Arrays.stream(strs)
                .map(Integer::parseInt)
                .collect(Collectors.toList());

        LinkedList<Integer> res = new LinkedList<>();

        for (int i = 0; i < height.size(); i++) {
            int pos = 0;
            for (int j = i + 1; j < height.size(); j++) {
                if (height.get(j) > height.get(i)) {
                    pos = j;
                    break;
                }
            }
            res.add(pos);
        }

        StringBuilder builder = new StringBuilder();
        res.forEach(x -> builder.append(x).append(" "));
        if (builder.length() > 1) {
            String substring = builder.substring(0, builder.length() - 1);
            System.out.println(substring);
        }

    }

    /**
     * 1.输入字符串s输出s中包含所有整数的最小和，
     说明：1字符串s只包含a~z,A~Z,+,-，
     2.合法的整数包括正整数，一个或者多个0-9组成，如：0,2,3,002,102
     3.负整数，负号开头，数字部分由一个或者多个0-9组成，如-2,-012,-23,-00023
     输入描述：包含数字的字符串
     输出描述：所有整数的最小和
     示例：
     输入：
     bb1234aa
     　输出
     10
     　输入：
     bb12-34aa
     　输出：
     -31
     说明：1+2-(34)=-31
     */
    public static void test082(){
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        // 将字符串转为字符数组
        char[] chars = line.toCharArray();
        int sum = 0;
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (c == '-') {
                int start = i;
                i++;
                while (i < chars.length && Character.isDigit(chars[i])){
                    i++;
                }
                // 截取负数
                String substring = line.substring(start, i);
                // 长度必须大于1才是完整的负数，否则只是一个‘-’
                if (substring.length() > 1) {
                    sum += Integer.parseInt(substring);
                }
                continue;
            }
            // 判断字符是否是数字
            if (Character.isDigit(c)) {
                // 将字符转为数字进行加法，如果数字字符的大小小于第二个参数，则返回-1(要进行加减，必须要将字符转过来)
                sum += Character.digit(c, 10);
            }
        }
        System.out.println(sum);
    }

    /**
     * 程序员小明打了一辆出租车去上班。出于职业敏感，他注意到这辆出租车的计费表有点问题，总是偏大。
     出租车司机解释说他不喜欢数字4，所以改装了计费表，任何数字位置遇到数字4就直接跳过，其余功能都正常。
     比如：
     1. 23再多一块钱就变为25；
     2. 39再多一块钱变为50；
     3. 399再多一块钱变为500；
     小明识破了司机的伎俩，准备利用自己的学识打败司机的阴谋。
     给出计费表的表面读数，返回实际产生的费用。

     输入描述:
     只有一行，数字N，表示里程表的读数。
     (1<=N<=888888888)。
     输出描述:
     一个数字，表示实际产生的费用。以回车结束。
     示例1：
     输入
     5
     输出
     4
     说明
     5表示计费表的表面读数。
     表示实际产生的费用其实只有4块钱。

     示例2：
     输入
     17
     输出
     15
     说明
     17表示计费表的表面读数。
     15表示实际产生的费用其实只有15块钱。
     示例3：
     输入
     100
     输出
     81
     说明：100表示计费表的表面读数，81表示实际产生的费用其实只有81块钱
     */
    // 数字4的个数
    public static void test081(){
        Scanner sc = new Scanner(System.in);
        int start = sc.nextInt();
        // 数字中有4的个数
        int sum = 0;
        for (int i = 1; i <= start; i++) {
            // 将数字转为字符串，判断数字是否包含4
            if ((i+"").contains("4")) {
                // 累加
                sum++;
            }
        }
        System.out.println(start - sum);
    }
    public static void test081_2(){
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int ans = N, temp = 0, k = 0, j = 1;
        while (N > 0) {
            //先判断个位上是否跳了4，如果个位上是5~9，就先temp=1。
            if (N % 10 > 4) {
                temp += (N % 10 - 1) * k + j;
            } else {
                temp += (N % 10) * k;
            }
            k = k * 9 + j;//k代表跳了多少次4，多收了多少个1元
            j *= 10;//j代表位数，1代表个位，10代表十位
            N /= 10;//相当于将N整体右移一位
        }
        System.out.println(ans - temp);
    }

    /**
     * 给定参数n,从1到n会有n个整数:1,2,3,...,n,
     这n个数字共有n!种排列.
     按大小顺序升序列出所有排列的情况,并一一标记,
     当n=3时,所有排列如下:
     "123" "132" "213" "231" "312" "321"
     给定n和k,返回第k个排列.

     输入描述:
     输入两行，第一行为n，第二行为k，
     给定n的范围是[1,9],给定k的范围是[1,n!]。
     输出描述：
     输出排在第k位置的数字。

     实例1：
     输入:
     3
     3
     输出：
     213
     说明
     3的排列有123,132,213...,那么第三位置就是213

     实例2：
     输入
     2
     2
     输出：
     21
     说明
     2的排列有12,21，那么第二位置的为21
     */
    // 整数排列
    public static void test080(){
        Scanner in = new Scanner(System.in);
        int n = Integer.parseInt(in.nextLine());
        int k = Integer.parseInt(in.nextLine());
        StringBuilder sb = new StringBuilder();

        List<Integer> candidates = new ArrayList<>();

        int[] factorials = new int[n + 1];
        factorials[0] = 1;
        int fact = 1;
        for (int i = 1; i <= n; ++i) {
            candidates.add(i);
            fact *= i;
            factorials[i] = fact;
        }
        k -= 1;
        for (int i = n - 1; i >= 0; --i) {
            // 计算候选数字的index
            int index = k / factorials[i];
            sb.append(candidates.remove(index));
            k -= index * factorials[i];
        }
        System.out.println(sb);
    }
}
